from copy import deepcopy
from pymongo import MongoClient


class Query:
    """
    与第三方数据库接口交互，用于处理数据查询请求，
    目前只实现了`retrieve`方法demo，
    计划可根据实际需求分类封装相应接口

    还需考虑是否要完善异常机制，
    是否需要统一异常接口

    还需考虑线程安全问题
    """

    def __init__(self, client_settings: dict):
        self.settings = deepcopy(client_settings)
        self._mongo = None
        self._mysql = None

    def connect(self, client):
        """
        数据库连接的设置信息规范后，
        此处直接调用
        按需连接，尽量降低服务端并发
        """

        if client == 'mongo' and self._mongo is not None:
            return
        if client == 'mysql' and self._mysql is not None:
            return

        if client == 'mongo':
            mongo_settings = {
                'host': self.settings['mongo_host'],
                'port': int(self.settings['mongo_port'])
            }
            if self.settings['mongo_user'] is not None:
                mongo_settings['username'] = self.settings['mongo_user']
            if self.settings['mongo_passwd'] is not None:
                mongo_settings['password'] = self.settings['mongo_passwd']

            self._mongo = MongoClient(**mongo_settings)
        elif client == 'mysql':
            pass  # demo省略mysql或其他数据库配置
        else:
            raise LookupError(f"没有{client}数据库。")

    def close(self):
        """
        该方法用于上层API实现上下文管理。
        但是实测PyMongo.MongoClient实例是否关闭区别不大
        就算关闭后，再调用也会自动重连，且实例占用资源不大

        考虑官方给了这个接口，应该还是有意义的。
        另外后期如果扩展其他数据库也能用上。
        """
        self._mongo.close()
        try:
            self._mysql.close()
        except AttributeError:
            pass

    def retrieve(self, request):
        """统一处理数据查询，这里需要和API.request方法统一接口"""

        # 连接数据库
        self.connect(request['client'])
        # 获取相应数据库对象
        if request['client'] == 'mongo':
            client: MongoClient = self._mongo
        elif request['client'] == 'mysql':
            raise NotImplementedError("mysql还没开发...")
        else:
            raise LookupError("没有这个数据库，请检查！")

        db = client[request['database']]
        collection = db[request['collection']]
        cursor = collection.find(request['query'])

        return cursor
